/**
 *  Created on  : 25 Noviembre de 2010
 *  Author      : Javier Silva Pérez
 *  Description :
 *              Clase que implementa la interfaz de la base de datos, obtiene conecciones
 *              y ejectua consultas e instrucciones
 */
package cinvestav.adviseme.databasemodel;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.sql.DataSource;

import cinvestav.adviseme.util.DBException;

/**
 *
 * @author Javier Silva Pérez
 */
public class DataBase implements IDataBase {

    private DataSource fuenteDatos;

    public DataBase() throws DBException{
        fuenteDatos=null;
        init();
    }

    /**
     * Crea el DataSource apartir del contexto de la aplicacion, busca el jdbc
     * señalado en el archivo de configuracion.
     * @throws DBException  Si no encuentra la referencia al JDBC en el contexto de la aplicacion
     */
    private void init() throws DBException {
        try {
            Context contextoInicial = new InitialContext(); // Equivalente: new InitialContext(null).
            Context contexto = (Context) contextoInicial.lookup("java:comp/env");
            //Busca en el contexto de la aplicacion un recurso ver web.xml para ver como se declara
            fuenteDatos = (DataSource) contexto.lookup("jdbc/adviseMeDB");
        } catch (NameNotFoundException e) {               // Hija de NamingException
            fuenteDatos = null;
            throw new DBException(e.getMessage(), e.getCause());
        } catch (Exception e) {
            fuenteDatos = null;
            throw new DBException(e.getMessage(), e.getCause());
        }
    }

    /**
     * Carga el archivo de configuración, en el cual se encuentra el JNDI del JDBC configurado
     * @return  Una cadena con el nombre del JDBC configurado
     * @throws DBException  Si el archivo no se pudo abrir.
     */
    private String getJDBCName() throws DBException {
        try {
            //Se declara el objeto de propiedades
            Properties props = new Properties();
            //Se lee el archivo
            File f = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile());
            FileInputStream fis = new FileInputStream(f.getParent() + "/config/conectionPoolConfig.properties");
            //Busca el archivo con los datos de configuracion
            props.load(fis);
            //Se obtienen los parametros
            String jndi = props.getProperty("@jndi");
            return jndi;
        } catch (IOException ex) {
            throw new DBException("Error loading the config file: \"/config/conectionPoolConfig.properties\" ");
        }
    }

    /**
     * Obtiene una conexion del pool
     * @return  Una conexion active del pool
     * @throws DBException
     */
    public Connection getConnection() throws DBException {
        try {
            //Si no se creo correctamente la fuente de datos.
            if (fuenteDatos == null) {
                throw new DBException("No existe fuente de datos creada");
            }
            return fuenteDatos.getConnection();
        } catch (Exception e) {
            throw new DBException(e.getMessage(), e.getCause());
        }

    }

    public DataSource getDataSource() {
        return this.fuenteDatos;
    }

    public void setDataSource(DataSource dataSource) {
        this.fuenteDatos = dataSource;
    }

    /**
     * Ejecuta una Instruccion en la base de datos (INSERT, UPDATE, DELETE, etc)
     * @param statement PreparedStatement que contiene la sentencia SQL
     * @throws DBException  Si ocurrio un error en la ejecucion  de la consulta
     */
    public void ejecutarInstruccion(PreparedStatement statement) throws DBException {
        //Se ejecuta la consulta
        try {
            statement.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(DataBase.class.getName()).log(Level.SEVERE, null, ex);
            throw new DBException("Ocurrio un Error al ejectuar la consulta: \n",ex);
        }
    }

    public ResultSet ejecutarQuery(PreparedStatement statement) throws DBException {
        ResultSet rs = null;
        //Se ejecuta la consulta
        try {
            rs = statement.executeQuery();
        } catch (SQLException ex) {
            Logger.getLogger(DataBase.class.getName()).log(Level.SEVERE, null, ex);
            throw new DBException("Ocurrio un Error al ejectuar la consulta: \n",ex);
        }
        return rs;
    }
    
}
